#include "TutorialApplication.h"
 
#include <OgreException.h>
#include <OgreConfigFile.h>
#include <OgreEntity.h>
 
//-------------------------------------------------------------------------------------
BasicTutorial6::BasicTutorial6(void)
    : mPluginsCfg(Ogre::StringUtil::BLANK),
      mResourcesCfg(Ogre::StringUtil::BLANK),
      mWindow(0),
      mSceneMgr(0) {
}
//-------------------------------------------------------------------------------------
BasicTutorial6::~BasicTutorial6(void) {
    Ogre::WindowEventUtilities::removeWindowEventListener(mWindow, this);
    windowClosed(mWindow);
}
 
bool BasicTutorial6::go(void) {
#ifdef _DEBUG
    mPluginsCfg = "plugins_d.cfg";
    mResourcesCfg = "resources_d.cfg";
#else
    mPluginsCfg = "plugins.cfg";
    mResourcesCfg = "resources.cfg";
#endif
    mRoot.reset(new Ogre::Root(mPluginsCfg));
    Ogre::ConfigFile cf;
    cf.load(mResourcesCfg);
    Ogre::String secName, typeName, archName;
    for (Ogre::ConfigFile::SectionIterator siter = cf.getSectionIterator(); siter.hasMoreElements(); ) {
        secName = siter.peekNextKey();
        Ogre::ConfigFile::SettingsMultiMap *settings = siter.getNext();
        for (Ogre::ConfigFile::SettingsMultiMap::iterator i = settings->begin(), iend = settings->end(); i != iend; ++i) {
            typeName = i->first;
            archName = i->second;
            Ogre::ResourceGroupManager::getSingleton().addResourceLocation(archName, typeName, secName);
        }

    }

    if (!(mRoot->restoreConfig() || mRoot->showConfigDialog()))
        return false;

    mWindow = mRoot->initialise(true, "BasicTutorial6 Render Window");

    Ogre::TextureManager::getSingleton().setDefaultNumMipmaps(5);
    Ogre::ResourceGroupManager::getSingleton().initialiseAllResourceGroups();

    mSceneMgr = mRoot->createSceneManager("DefaultSceneManager");
    mCamera = mSceneMgr->createCamera("PlayerCam");
    mCamera->setPosition(Ogre::Vector3(0, 0, 80));
    mCamera->lookAt(Ogre::Vector3(0, 0, -300));
    mCamera->setNearClipDistance(5);
    
    Ogre::Viewport *vp = mWindow->addViewport(mCamera);
    vp->setBackgroundColour(Ogre::ColourValue(0, 0, 0));
    mCamera->setAspectRatio( Ogre::Real(vp->getActualWidth()) / Ogre::Real(vp->getActualHeight()) );

    // creating scene
    Ogre::Entity *ogreHead = mSceneMgr->createEntity("Head", "ogrehead.mesh");
    Ogre::SceneNode *headNode = mSceneMgr->getRootSceneNode()->createChildSceneNode();
    headNode->attachObject(ogreHead);

    mSceneMgr->setAmbientLight(Ogre::ColourValue(.5, .5, .5));

    Ogre::Light *l = mSceneMgr->createLight("MainLight");
    l->setPosition(20, 80, 50);

    // initializing OIS
    Ogre::LogManager::getSingletonPtr()->logMessage("*** Initializing OIS ***");
    OIS::ParamList pl;
    size_t windowHnd = 0;
    std::ostringstream windowHndStr;

    mWindow->getCustomAttribute("WINDOW", &windowHnd);
    windowHndStr << windowHnd;
    pl.insert(std::make_pair(std::string("WINDOW"), windowHndStr.str()));

    mInputManager = OIS::InputManager::createInputSystem(pl);
    const bool bufferedInput = false;
    mKeyboard = static_cast<OIS::Keyboard*>(mInputManager->createInputObject(OIS::OISKeyboard, bufferedInput));
    mMouse = static_cast<OIS::Mouse*>(mInputManager->createInputObject(OIS::OISMouse, bufferedInput));

    windowResized(mWindow);
    Ogre::WindowEventUtilities::addWindowEventListener(mWindow, this);

    // render loop
    /*for (;;) {
        Ogre::WindowEventUtilities::messagePump();
        if (mWindow->isClosed())
            return false;
        if (!mRoot->renderOneFrame())
            return false;
    }*/
    mRoot->addFrameListener(this);
    mRoot->startRendering();
    
    return true;
}
 
void BasicTutorial6::windowResized(Ogre::RenderWindow *rw) {
    unsigned int width, height, depth;
    int left, top;
    rw->getMetrics(width, height, depth, left, top);

    const OIS::MouseState &ms = mMouse->getMouseState();
    ms.width = width;
    ms.height = height;
}

void BasicTutorial6::windowClosed(Ogre::RenderWindow *rw) {
    if (rw == mWindow) {
        if (mInputManager) {
            mInputManager->destroyInputObject(mMouse);
            mInputManager->destroyInputObject(mKeyboard);

            OIS::InputManager::destroyInputSystem(mInputManager);
            mInputManager = 0;
        }
    }
}
 
bool BasicTutorial6::frameRenderingQueued(const Ogre::FrameEvent &evt) {
    if (mWindow->isClosed())
        return false;

    mKeyboard->capture();
    mMouse->capture();

    if (mKeyboard->isKeyDown(OIS::KC_ESCAPE))
        return false;

    return true;
}

#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
#define WIN32_LEAN_AND_MEAN
#include "windows.h"
#endif
 
#ifdef __cplusplus
extern "C" {
#endif
 
#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
    INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR strCmdLine, INT )
#else
    int main(int argc, char *argv[])
#endif
    {
        // Create application object
        BasicTutorial6 app;
 
        try {
            app.go();
        } catch( Ogre::Exception& e ) {
#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
            MessageBox( NULL, e.getFullDescription().c_str(), "An exception has occured!", MB_OK | MB_ICONERROR | MB_TASKMODAL);
#else
            std::cerr << "An exception has occured: " <<
                e.getFullDescription().c_str() << std::endl;
#endif
        }
 
        return 0;
    }
 
#ifdef __cplusplus
}
#endif
